package org.chemodansama.fifteen;

import static org.chemodansama.engine.render.imgui.NpGuiReturnConsts.clicked;
import static org.chemodansama.engine.render.imgui.NpGuiReturnConsts.mouseMovedIn;

import javax.microedition.khronos.opengles.GL10;

import static org.chemodansama.engine.render.imgui.NpAlignConsts.*;

import org.chemodansama.engine.NpSoundMan;
import org.chemodansama.engine.math.NpRect;
import org.chemodansama.engine.math.NpVec4;
import org.chemodansama.engine.render.imgui.NpAlignConsts;
import org.chemodansama.engine.render.imgui.NpFontParams;
import org.chemodansama.engine.render.imgui.NpSkin;
import org.chemodansama.engine.render.imgui.NpWidgetState;

public class Panels implements FifteenConsts {
    private static final String TOP_BG = "15TopBg";
    private static final String TOP_BTN = "15TopBtn";
    private static final String BG = "15Bg";
    private static final String TOP_PANE = "15TopPane";
    private static final String BOTTOM_PANE = "15BottomPane";
    
    private static final String TIME_WIDGET = "15time";
    private static final String MOVES_WIDGET = "15moves";
    
    private static final NpFontParams COUNT_FONT = 
        new NpFontParams("neuro24", 30, COLOR_WHITE);
    
    private static final NpFontParams TIME_FONT = 
        new NpFontParams("neuro24", 25, COLOR_WHITE);
    
    private static final NpFontParams TIME_FONT_ELAPSED = 
        new NpFontParams("neuro24", 25, COLOR_YELLOW);
    
    private static final int TIME_LIMIT = 9;
    
    private static final NpFontParams NEURO19 = 
        new NpFontParams("neuro24", 19, COLOR_WHITE);
    
    static abstract class NpClickListener {
        abstract void onClick();
    }
    
    static abstract class NpActionWithGL {
        boolean ready = false;
        boolean rendered = false;
        abstract void action(GL10 gl);
    }
    
    private static NpActionWithGL mActionOnPanelsClosed = null;
    private static double mTopPanelPos = 0;
    private static boolean mIsSliding = false;
    private static double mDelayToOpen = -1;
    
    private static boolean mWantTopBtns = true;
    private static double mTopBtnsPos = 1;
    private static boolean mTopBtnIsMoving = false;
    
    private static boolean mWantBottomBtns = false;
    private static double mBottomBtnsPos = 0;
    private static boolean mBottomBtnIsMoving = false;
    
    private static boolean mCanSlide = true;
    
    static int movesCount = 0;
    static long time = 0;
    
    private static NpSoundMan mSoundMan = null;
    private static GL10 mGL = null;
    private final static NpVec4 mLabelsClr = new NpVec4(1, 1, 1, 0);
    
    public static void setActionOnClosed(NpActionWithGL action) {
        if (mActionOnPanelsClosed != null) {
            return;
        }
        
        mActionOnPanelsClosed = action;
        mWantTopBtns = true;
        mCanSlide = false;
    }
    
    public static void enableTopBtns() {
        mWantTopBtns = true;
    }
    
    public static void disableTopBtns() {
        mWantTopBtns = false;
    }
    
    public static void enableBottomBtns() {
        mWantBottomBtns = true;
    }
    
    public static void disableBottomBtns() {
        mWantBottomBtns = false;
    }
    
    private static double computeTopPanelDelta(double deltaInSecs) {
        return deltaInSecs * (0.66 + 6 * (1 - mTopPanelPos));
    }
    
    static void drawBg(int surfaceWidth, int surfaceHeight) {
        final NpRect bgRect = new NpRect(0, 0, surfaceWidth, surfaceHeight);
        
        NpSkin.doRectWidget(NpWidgetState.WS_NORMAL, BG, bgRect);
    }
    
    static void drawBottomPane(int surfaceWidth, int surfaceHeight) {
        drawBottomPane(surfaceWidth, surfaceHeight, null, null);
    }
    
    static void drawBottomPane(int surfaceWidth, int surfaceHeight, 
            NpClickListener onMenuClicked, NpClickListener onZoomClicked) {
        final NpRect bottomImageRect = new NpRect();
        if (!NpSkin.getImageRect(BOTTOM_PANE, NpWidgetState.WS_NORMAL, 
                                 "Panel", bottomImageRect)) {
            // the widget is not found?! what a terrible failure?
            bottomImageRect.set(0, 0, 480, 108);
        }
        
        final NpRect bottomBtnRect = new NpRect();
        if (!NpSkin.getImageRect("15BottomBtn", NpWidgetState.WS_NORMAL, 
                                 "TopEdge", bottomBtnRect)) {
            bottomBtnRect.set(0, 0, 141, 76);
        }
        
        final int btnW = bottomBtnRect.w;
        final int btnY = surfaceHeight - 49 - bottomBtnRect.h / 2;
        
        bottomBtnRect.y = btnY;

        bottomBtnRect.x = 0;
        NpSkin.doRectWidget(NpWidgetState.WS_NORMAL, BG, bottomBtnRect);
        
        bottomBtnRect.x = surfaceWidth - btnW;
        NpSkin.doRectWidget(NpWidgetState.WS_NORMAL, BG, bottomBtnRect);
        
        int bottomHeight = bottomImageRect.h;

        final NpRect bottomRect = new NpRect(0, surfaceHeight - bottomHeight, 
                                             surfaceWidth, bottomHeight);
        
        NpSkin.doRectWidget(NpWidgetState.WS_NORMAL, BOTTOM_PANE, bottomRect);
        
        int r = 0;
        
        bottomBtnRect.x = (int) ((mBottomBtnsPos - 1) * btnW);
        r = NpSkin.doButton("15BottomBtn", "Menu", NEURO19, bottomBtnRect);

        if (mouseMovedIn(r)) {
            mSoundMan.addSound(R.raw.btn);
            mSoundMan.playSound(R.raw.btn);
        }
        
        if (clicked(r) && (onMenuClicked != null)) {
            onMenuClicked.onClick();
        }
        
        bottomBtnRect.x = surfaceWidth - (int) (btnW * mBottomBtnsPos);
        r = NpSkin.doButtonEx("15BottomBtn", "Zoom", NEURO19, bottomBtnRect, 
                              true, false);
        
        if (mouseMovedIn(r)) {
            mSoundMan.addSound(R.raw.btn);
            mSoundMan.playSound(R.raw.btn);
        }
        
        if (clicked(r) && (onZoomClicked != null)) {
            onZoomClicked.onClick();
        }
    }
    
    static void drawTopPanel(int surfaceWidth, int surfaceHeight) {
        
        final NpRect topImageRect = new NpRect();
        if (!NpSkin.getImageRect(TOP_PANE, NpWidgetState.WS_NORMAL, 
                                 "Panel", topImageRect)) {
            topImageRect.set(0, 0, 480, 140);
        }
        
        int topHeight = topImageRect.h;
        
        int bottomContactHeight = 80;
        int lowerLimit = surfaceHeight - bottomContactHeight - topHeight;
        
        int topY = (int) (lowerLimit * mTopPanelPos);
        
        // draw buttons bg 
        
        final NpRect topBtnRect = new NpRect();
        if (!NpSkin.getImageRect(TOP_BTN, NpWidgetState.WS_NORMAL, 
                                 "TopEdge", topBtnRect)) {
            topBtnRect.set(0, 0, 119, 72);
        }
        
        final int btnW = topBtnRect.w;
        topBtnRect.y = topY + 20;

        topBtnRect.x = 0;
        NpSkin.doRectWidget(NpWidgetState.WS_NORMAL, BG, topBtnRect);
        
        topBtnRect.x = (int) (surfaceWidth - btnW);
        NpSkin.doRectWidget(NpWidgetState.WS_NORMAL, BG, topBtnRect);
        
        int movesX = surfaceWidth - 52;
        int movesY = 68;
        
        NpSkin.doLabel(movesX, movesY, Integer.toString(movesCount), COUNT_FONT, 
                       NpAlignConsts.ALIGN_CENTER);
        
        long timeInSec = Math.round(time / 1E+09d);
        int mins = (int) timeInSec / 60;
        int secs = (int) timeInSec - 60 * mins;
        
        NpFontParams font;
        
        if (mins <= TIME_LIMIT) {
            font = TIME_FONT;
            
        } else {
            mins = TIME_LIMIT;
            secs = 59;
            font = TIME_FONT_ELAPSED;
        }
        
        String minute = Integer.toString(mins);
        String second = Integer.toString(secs);
        if (secs < 10) {
            second = "0" + second;
        }
        
        int timerX = 52;
        int timerY = 68;
        String curTime = minute + ":" + second;        
        NpSkin.doLabel(timerX, timerY, curTime, font, ALIGN_CENTER);
        
        // draw top panel and bg on it
        
        final NpRect bgRect = new NpRect(0, 0, surfaceWidth, topY);
        
        NpSkin.doRectWidget(NpWidgetState.WS_NORMAL, TOP_BG, bgRect);
        
        final NpRect topRect = new NpRect(0, topY, surfaceWidth, topHeight);
        
        NpSkin.doRectWidget(NpWidgetState.WS_NORMAL, TOP_PANE, topRect);
        
        // draw buttons
        
        topBtnRect.x = (int) (btnW * (mTopBtnsPos - 1));
        NpSkin.doRectWidget(NpWidgetState.WS_NORMAL, TOP_BTN, topBtnRect);
        
        topBtnRect.x = (int) (surfaceWidth - mTopBtnsPos * btnW);
        NpSkin.doRectWidgetEx(NpWidgetState.WS_NORMAL, TOP_BTN, topBtnRect, 
                              true, false, NpVec4.ONE);
        
        
        final NpRect movesRect = new NpRect();
        if (!NpSkin.getImageRect(TIME_WIDGET, NpWidgetState.WS_NORMAL, 
                                 "TopEdge", movesRect)) {
            topBtnRect.set(0, 0, 113, 30);
        }
        
        movesRect.x = 0;
        movesRect.y = topBtnRect.y + topBtnRect.h;
        NpSkin.doRectWidgetEx(NpWidgetState.WS_NORMAL, TIME_WIDGET, movesRect,
                              false, false, mLabelsClr);
        
        movesRect.x = (int) (surfaceWidth - movesRect.w);
        NpSkin.doRectWidgetEx(NpWidgetState.WS_NORMAL, MOVES_WIDGET, movesRect,
                              false, false, mLabelsClr);
    }
    
    static void preRender(NpSoundMan sm, GL10 gl) {
        mSoundMan = sm;
        mGL = gl;
    }
    
    static void postRender() {
        if ((mActionOnPanelsClosed != null) && (mActionOnPanelsClosed.ready)) {

            // introduce one-frame delay, for buffers to be swapped
            if (mActionOnPanelsClosed.rendered) {
                mActionOnPanelsClosed.action(mGL);
                mActionOnPanelsClosed = null;
                
                mSoundMan.addSound(R.raw.pane);
                mSoundMan.playSound(R.raw.pane);
            } else {
                mActionOnPanelsClosed.rendered = true;
            }
        }
    }
    
    private static double computeTopBtnsDelta(double deltaInSecs) {
        return deltaInSecs * (1 + 10 * (1 - mTopBtnsPos));
    }
    
    private static double computeBottomBtnsDelta(double deltaInSecs) {
        return deltaInSecs * (1 + 10 * (1 - mBottomBtnsPos));
    }
    
    static void update(NpSoundMan sm, double deltaInSecs) {
        if (mActionOnPanelsClosed != null) {
            if (mCanSlide) {
                mIsSliding = true;
                if (mDelayToOpen > 0) {
                    mDelayToOpen -= deltaInSecs;
                    if (mDelayToOpen < 0) {
                        mActionOnPanelsClosed.ready = true;
                    }
                } else if (!mActionOnPanelsClosed.ready) {
                    mTopPanelPos += computeTopPanelDelta(deltaInSecs);

                    if (mTopPanelPos > 1) {
                        mTopPanelPos = 1;

                        mDelayToOpen = 0.25;
                    }
                }
            } else {
                mIsSliding = false;
            }
        } else if (mTopPanelPos > 0) {
            mTopPanelPos -= computeTopPanelDelta(deltaInSecs);
            
            if (mTopPanelPos < 0) {
                mIsSliding = false;
                mTopPanelPos = 0;
            } else {
                mIsSliding = true;
            }
        } else {
            mIsSliding = false;
            mTopPanelPos = 0;
        }
        
        if (!mIsSliding) {
            if (mWantBottomBtns) {
                if (mBottomBtnsPos < 1) {
                    if (!mBottomBtnIsMoving) {
                        sm.addSound(R.raw.pane_btn_in);
                        sm.playSound(R.raw.pane_btn_in);
                    }
                    
                    mBottomBtnsPos += computeBottomBtnsDelta(deltaInSecs);
                    
                    if (mBottomBtnsPos > 1) {
                        mBottomBtnsPos = 1;
                        mBottomBtnIsMoving = false;
                    } else {
                        mBottomBtnIsMoving = true;
                    }
                } else {
                    mBottomBtnsPos = 1;
                    mBottomBtnIsMoving = false;
                }
            } else {
                if (mBottomBtnsPos > 0) {
                    if (!mBottomBtnIsMoving) {
                        sm.addSound(R.raw.pane_btn_out);
                        sm.playSound(R.raw.pane_btn_out);
                    }
                    
                    mBottomBtnsPos -= computeBottomBtnsDelta(deltaInSecs);
                    
                    if (mBottomBtnsPos < 0) {
                        mBottomBtnsPos = 0;
                        mBottomBtnIsMoving = false;
                    } else {
                        mBottomBtnIsMoving = true;
                    }
                } else {
                    mBottomBtnsPos = 0;
                    mBottomBtnIsMoving = false;
                }
            }
            
            if (mWantTopBtns) {
                if (mTopBtnsPos < 1) {
                    if (!mTopBtnIsMoving) {
                        sm.addSound(R.raw.pane_btn_in);
                        sm.playSound(R.raw.pane_btn_in);
                    }                    
                    
                    mTopBtnsPos += computeTopBtnsDelta(deltaInSecs);

                    if (mTopBtnsPos > 1) {
                        mTopBtnsPos = 1;
                        mTopBtnIsMoving = false;
                    } else {
                        mTopBtnIsMoving = true;
                    }
                } else {
                    mTopBtnsPos = 1;
                    mTopBtnIsMoving = false;
                }
            } else {
                if (mTopBtnsPos > 0) {
                    if (!mTopBtnIsMoving) {
                        sm.addSound(R.raw.pane_btn_out);
                        sm.playSound(R.raw.pane_btn_out);
                    }       
                    
                    mTopBtnsPos -= computeTopBtnsDelta(deltaInSecs);
                    
                    if (mTopBtnsPos < 0) {
                        mTopBtnsPos = 0;
                        mTopBtnIsMoving = false;
                    } else {
                        mTopBtnIsMoving = true;
                    }
                } else {
                    mTopBtnsPos = 0;
                    mTopBtnIsMoving = false;
                }
            }
            
            mLabelsClr.setW((float)(1 - mTopBtnsPos));
            
            boolean r = !mBottomBtnIsMoving && !mTopBtnIsMoving;
            
            if (!mCanSlide && r && (mActionOnPanelsClosed != null)) {
                sm.addSound(R.raw.pane);
                sm.playSound(R.raw.pane);
            }
            
            mCanSlide = r;
        }
    }
}
